package com.lagou.edu.factory;

import com.lagou.edu.annotation.*;
import com.lagou.edu.utils.ClassUtils;
import com.mysql.cj.util.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * 任务一:读取解析xml，通过反射技术实例化bean并将其存储在map中待用
     *
     * 任务二:对外提供获取实例的方法
     */

    private static Map<String,Object> beans = new HashMap<>();//存储对象

    static {
        List<String> classPathsByPackage = ClassUtils.getClassPathsByPackage("com.lagou.edu");
        try {
            for (String classPaths : classPathsByPackage) {
                Class<?> aClass = Class.forName(classPaths);
                Annotation[] annotations = aClass.getDeclaredAnnotations();
                boolean isAdd = false;
                String id = "";
                for (Annotation annotation : annotations) {
                    if (annotation instanceof Component||annotation instanceof Repository ||annotation instanceof Service){
                        isAdd = true;
                    }
                    if (annotation instanceof Component){
                        Component component = (Component) annotation;
                        id = component.value();
                    }
                    if (annotation instanceof Repository){
                        Repository component = (Repository) annotation;
                        id = component.value();
                    }
                    if (annotation instanceof Service){
                        Service component = (Service) annotation;
                        id = component.value();
                    }

                }
                if(isAdd){
                    if("".equals(id)){
                        id=lowerFirstChar(aClass.getSimpleName());
                    }
                    Object o = aClass.newInstance();
                    beans.put(id,o);
                    beans.put(aClass.getName(),o);
                    Class<?>[] interfaces = aClass.getInterfaces();
                    if (interfaces.length>0){
                        for (Class<?> anInterface : interfaces) {
                            String interfaceName = anInterface.getName();
                            beans.put(interfaceName,o);
                        }
                    }
                }
            }

            for (String classPaths : classPathsByPackage) {
                Class<?> aClass = Class.forName(classPaths);
                Annotation[] annotations = aClass.getAnnotations();
                boolean isAdd = false;
                String id = "";
                for (Annotation annotation : annotations) {
                    if (annotation instanceof Component||annotation instanceof Repository ||annotation instanceof Service){
                        isAdd = true;
                    }
                    if (annotation instanceof Component){
                        Component component = (Component) annotation;
                        id = component.value();
                    }
                    if (annotation instanceof Repository){
                        Repository component = (Repository) annotation;
                        id = component.value();
                    }
                    if (annotation instanceof Service){
                        Service component = (Service) annotation;
                        id = component.value();
                    }

                }
                if(isAdd){
                    Field[] declaredFields = aClass.getDeclaredFields();
                    if("".equals(id)){
                        id = lowerFirstChar(aClass.getSimpleName());
                    }
                    if (declaredFields.length>0){
                        for (Field declaredField : declaredFields) {
                            Annotation[] fieldAnnotations = declaredField.getDeclaredAnnotations();
                            for (Annotation fieldAnnotation : fieldAnnotations) {
                                if(fieldAnnotation instanceof Autowired){
                                    String fieldTypeName = declaredField.getType().getName();
                                    Object o = beans.get(fieldTypeName);
                                    Object o1 = beans.get(id);
                                    String name = declaredField.getName();
                                    Field field = o1.getClass().getDeclaredField(name);
                                    field.setAccessible(true);
                                    field.set(o1,o);
                                }
                            }
                        }
                    }
                    Method[] methods = aClass.getMethods();
                    if(methods.length>0){
                        for (Method method : methods) {
                            Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
                            boolean isProxy = false;
                            if(declaredAnnotations.length>0){
                                for (Annotation declaredAnnotation : declaredAnnotations) {
                                    if(declaredAnnotation instanceof Transactional){
                                        isProxy = true;
                                    }
                                }
                            }
                            if(isProxy){
                                ProxyFactory proxyFactory = (ProxyFactory)beans.get("proxyFactory");
                                Object o = beans.get(id);
                                Object proxyObj = null;
                                if(aClass.getInterfaces().length>0){
                                    proxyObj = proxyFactory.getJdkProxy(o);
                                }else{
                                    proxyObj = proxyFactory.getCglibProxy(o);
                                }
                                Class<?> aClass1 = o.getClass();
                                String name = aClass1.getName();
                                beans.put(id,proxyObj);
                                beans.put(name,proxyObj);
                                Class<?>[] interfaces = aClass1.getInterfaces();
                                if(interfaces.length>0){
                                    for (Class<?> anInterface : interfaces) {
                                        String name1 = anInterface.getName();
                                        beans.put(name1,proxyObj);
                                    }
                                }
                            }
                        }
                    }
                }
            }


            System.out.println("初始化完成！");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }

    private static String lowerFirstChar(String str) {
        char[] chars = str.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    /**
     * 根据id获取实例化对象
     * @param id
     * @return
     */
    public static Object getBean(String id){
        return beans.get(id);
    }

}
